Referring to FIG. 1, there is depicted a compilation environment 100 including source code 102, compiler 104, assembler code 106 or 108, and respective executable code 116 or 118. Compiler 104 compiles source code 102 to generate either assembler code 106 or 108 depending upon optimization routines used by compiler 104. Source code 102 includes computer programmed instructions written in a computer programming language such as Java, C++ or FORTRAN. Source code 102 is machine independent, which means that the source code includes generic programmed instructions 110A, 110B, 110C which are not yet in a form that is executable by any specific Central Processing Unit (CPU). Advantageously, compiler 104 compiles source code 102 to generate assembler code 106 or 108 which is executable by a specific type of CPU (sometimes referred to as a machine). Compiler 104 generates either assembler code 106 or 108 depending on the programmed instructions of the optimization routines used by compiler 104 when compiler 104 optimizes the instructions included in source code 102.
Compiler 104 performs several optimization phases to achieve several objectives. During the optimization phases, the instructions of source code 102 are replaced with machine-level instructions that are executable by a specific CPU and the machine-level instructions are repositioned, shuffled, or relocated with respect to other machine-level instructions in an attempt to produce executable code which is capable of being, for example, quickly executed or to produce minimized file size of the executable code for reducing dependency on computer memory (or a combination of both). After machine-level code 106 or 108 (sometimes referred to as assembler code) is generated, compiler 104 completes its task by generating a respective machine-executable code 116 or 118.
Assembler code 106 includes assembler-level computer instructions 112A to 112F that are machine dependent which means the assembler-level instructions can instruct a specific type of CPU. Compiler 104 uses the assembler code 106 to generate executable code 116 that can be executed. When compiler 104 uses one type of optimization routine, code 106 is generated having instructions 112A to 112F ordered or placed in the sequence depicted in FIG. 1. When compiler 104 uses another type of optimization routine, code 108 is generated having instructions 114A to 114F ordered or placed in the sequence depicted in FIG. 1 which is a different sequence of instructions when compared to code 106.
Executable code 116 includes an arrangement of contiguous portions (not depicted) corresponding to executable code of the assembler-level instructions 112A to 112F. The arrangement of the contiguous portions of executable code cannot be rearranged once the executable code 116 is generated by compiler 104. For the case when instruction 112C is executed more frequently than instruction 112E, it is advantageous to position or place instruction 112C in an execution fall through path immediately after instruction 112B, and to place instruction 112E offset from instruction 112B because execution time is not wasted in performing a branching operation for an instruction having a very high possibility (statistically) of being executed. However, for the case where instruction 112E is executed more frequently than instruction 112C, then it would be advantageous to position instruction 112E in the fall through path immediately after instruction 112B (which is the desirable ordering as depicted in code 108), and instruction 112C is placed offset from instruction 112B.
It will be appreciated that if code 106 were to be executed for the second case, then disadvantageously the execution fall through path proceeds, jumps, or branches from instruction 112B to instruction 112E on a frequent basis which will then require additional CPU processing time. It is a known problem that CPUs require extra time when executing branching instructions. For the second case, it would be highly desirable to place instruction 112E in an position adjacent to instruction 112B and locating instruction 112C offset from instruction 112B. It will be appreciated that code 108 is the preferred code for the second case, and code 106 is the preferred code for the first case. It is desirable to avoid spending time performing branching instructions whenever possible.
During optimization phases of a compiler, the compiler changes or transforms machine-independent code (also known as high-level code) into machine-dependent code (also known as low-level code or assemble code). From an optimization phase to a subsequent optimization phase, the compiler attempts to relocate or position units of transformed code relative to other units of transformed code by following known optimization algorithms. Transformed code is also known as intermediate representation (IR) code.
For a compilation pass of a compiler, the compiler reads machine-independent code and generates computer-executable, machine-dependent code via a series of optimization phases. During a first optimization phase of the compiler, profile directed feedback (PDF) counters (also known generically as ‘counters’) are inserted into machine-dependent code generated or created during a later or last optimization phase. Executable code, generated as a result of completing the first optimization pass, is made to interact with test data to subsequently generate statistical execution data which is captured by the inserted counters. It will be appreciated that the statistical execution data is related to the machine-dependent code that was formed during the latter or last optimization phase.
During a second compilation pass of the compiler, the compiler reads the machine-independent code and the captured counter data, optimizes the code during its optimization phases, and uses the captured counter data to specifically optimize code during the latter or last optimization phase. The captured counter data relates to the machine-dependent code (and is not related to the machine-independent code). An improved optimizing compiler is desired.